/*******************************************************************************
 * Copyright (c) 2008-2009 zhang yuexiang.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 
package org.xfeep.asura.bootstrap.config;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;


import com.sun.xml.internal.bind.v2.model.annotation.AbstractInlineAnnotationReaderImpl;
import com.sun.xml.internal.bind.v2.model.annotation.Locatable;
import com.sun.xml.internal.bind.v2.model.annotation.RuntimeAnnotationReader;
import com.sun.xml.internal.bind.v2.model.annotation.RuntimeInlineAnnotationReader;
import com.sun.xml.internal.bind.v2.model.core.ErrorHandler;

@SuppressWarnings("unchecked")
public class JaxbDirectListAnnotationReader extends AbstractInlineAnnotationReaderImpl<Type, Class, Field, Method> implements RuntimeAnnotationReader  {
	
//	public Class<?> elementType; // the type of elements in the list
	protected JaxbXmlElementMock xmlElementMock;
	protected RuntimeInlineAnnotationReader inlineAnnotationReader;
//	protected Map<Class, JaxbXmlTypeMock> xmlTypeMockCache;
//	protected Map<Field, JaxbXmlElementMock> xmlElementMockCache;
//	protected TypeInfoPool typeInfoPool;
	
	public static JaxbXmlTypeMock defaultJaxbXmlTypeMock = new JaxbXmlTypeMock();
	public static JaxbXmlElementMock defaultJaxbXmlElementMock = new JaxbXmlElementMock();
	public static JaxbXmlElementMock[] defaultJaxbXmlElementMockArray = new JaxbXmlElementMock[] {defaultJaxbXmlElementMock};
	
	public Annotation[] getAllMethodAnnotations(Method arg0, Locatable arg1) {
		return inlineAnnotationReader.getAllMethodAnnotations(arg0, arg1);
	}

	public <A extends Annotation> A getClassAnnotation(Class<A> ann,
			Class arg1, Locatable arg2) {
		A rt =  inlineAnnotationReader.getClassAnnotation(ann, arg1, arg2);
		if (rt == null && ann == XmlType.class){
			rt = (A)defaultJaxbXmlTypeMock;
		}
		return rt;
	}

	public Class[] getClassArrayValue(Annotation arg0, String arg1) {
		return inlineAnnotationReader.getClassArrayValue(arg0, arg1);
	}

	public Class getClassValue(Annotation arg0, String arg1) {
		return inlineAnnotationReader.getClassValue(arg0, arg1);
	}

	public <A extends Annotation> A getMethodAnnotation(Class<A> arg0,
			Method arg1, Locatable arg2) {
		return inlineAnnotationReader.getMethodAnnotation(arg0, arg1, arg2);
	}

	public <A extends Annotation> A getMethodParameterAnnotation(Class<A> arg0,
			Method arg1, int arg2, Locatable arg3) {
		return inlineAnnotationReader.getMethodParameterAnnotation(arg0, arg1,
				arg2, arg3);
	}

	public <A extends Annotation> A getPackageAnnotation(Class<A> arg0,
			Class arg1, Locatable arg2) {
		return inlineAnnotationReader.getPackageAnnotation(arg0, arg1, arg2);
	}

	public boolean hasMethodAnnotation(Class<? extends Annotation> arg0,
			Method arg1) {
		return inlineAnnotationReader.hasMethodAnnotation(arg0, arg1);
	}

	public boolean hasMethodAnnotation(Class<? extends Annotation> arg0,
			String arg1, Method arg2, Method arg3, Locatable arg4) {
		return inlineAnnotationReader.hasMethodAnnotation(arg0, arg1, arg2,
				arg3, arg4);
	}

	public void setErrorHandler(ErrorHandler arg0) {
		inlineAnnotationReader.setErrorHandler(arg0);
	}

	public JaxbDirectListAnnotationReader(Class<?> elementType) {
		xmlElementMock = new JaxbXmlElementMock();
		xmlElementMock.type = elementType;
		xmlElementMock.name = elementType.getSimpleName();
		inlineAnnotationReader = new RuntimeInlineAnnotationReader();
//		typeInfoPool = new TypeInfoPool();
	}

    public <A extends Annotation> A getFieldAnnotation(Class<A> annotation, Field field, Locatable srcPos) {
        if (annotation == XmlElement.class && field.getDeclaringClass() == DirectListJaxbWrapper.class){
        	return (A)xmlElementMock;
        }
    	
    	A rt = inlineAnnotationReader.getFieldAnnotation(annotation, field, srcPos);
    	if (rt == null && annotation == XmlElement.class ){
    		rt = (A)defaultJaxbXmlElementMock;
    	}
    	return rt;
    }

    public boolean hasFieldAnnotation(Class<? extends Annotation> annotationType, Field field) {
//    	if (annotationType == XmlElement.class && field.getDeclaringClass() == DirectListJaxbWrapper.class){
//    		return true;
//    	}
    	if (annotationType == XmlTransient.class){
    		return inlineAnnotationReader.hasFieldAnnotation(annotationType, field); 
    	}
    	boolean rt = inlineAnnotationReader.hasFieldAnnotation(annotationType, field);
    	if (!rt){
    		rt = annotationType == XmlElement.class;
    	}
    	return rt;
//      return inlineAnnotationReader.hasFieldAnnotation(annotationType, field);
    }

    public boolean hasClassAnnotation(Class clazz, Class<? extends Annotation> annotationType) {
    	if (annotationType == XmlTransient.class){
    		return inlineAnnotationReader.hasClassAnnotation(clazz, annotationType); 
    	}
    	boolean rt = inlineAnnotationReader.hasClassAnnotation(clazz, annotationType);
    	if (!rt){
    		rt = annotationType == XmlType.class;
    	}
    	return rt;
    }

    public Annotation[] getAllFieldAnnotations(Field field, Locatable srcPos) {
    	 if (field.getDeclaringClass() == DirectListJaxbWrapper.class){
         	return new Annotation[]{xmlElementMock};
         }
    	 Annotation[] rt = inlineAnnotationReader.getAllFieldAnnotations(field, srcPos);
    	 if (rt == null || rt.length == 0){
    		 rt = defaultJaxbXmlElementMockArray;
    	 }
    	 boolean hasXmlTransient = false;
    	 boolean hasXmlElement = false;
    	 for (Annotation a : rt){
    		 if (a.getClass() == XmlTransient.class){
    			 hasXmlTransient = true;
    			 break;
    		 }else if (a.getClass() == XmlElement.class){
    			 hasXmlElement = true;
    		 }
    	 }
    	 return (hasXmlTransient || hasXmlElement) ? rt : defaultJaxbXmlElementMockArray;
    }

	@Override
	protected String fullName(Method m) {
		return m.getDeclaringClass().getName()+'#'+m.getName();
	}



}
